package cn.jisol.ngame.demo.game.action.picopark.service;

import cn.jisol.ngame.demo.client.picopark.PicoparkNClient;
import cn.jisol.ngame.demo.entity.picopark.PicoparkRoom;
import cn.jisol.ngame.ncall.NCallServiceImpl;
import cn.jisol.ngame.rpc.NGameRPCClass;
import cn.jisol.ngame.rpc.NGameRPCMethod;
import cn.jisol.ngame.rpc.NRPCParam;
import cn.jisol.ngame.sync.NFPSInfo;
import cn.jisol.ngame.sync.fps.NSyncFPSMethod;
import cn.jisol.ngame.sync.fps.NSyncFPSMode;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;


/**
 * Cocos Frame 服务端 Action
 */
@Component
@NGameRPCClass
public class SNPicoparkAction extends NCallServiceImpl {

    @Autowired
    private Environment env;

    //同步nSyncModes
    public NSyncFPSMode<Object> nSyncFPSMode = null;

    //客户端列表
    public Map<String, PicoparkNClient> clients = null;

    //房间
    public PicoparkRoom room;

    //日志
    public Map<String,StringBuilder> logs = new HashMap<String,StringBuilder>();

    @NGameRPCMethod
    public void nHelloWorld(PicoparkNClient client){
        System.out.println(String.format("%s客户端 - nHelloWorld",client.getUuid()));
    }

    /**
     * 向帧同步添加输入
     * @param inputs 输入
     */
    @NGameRPCMethod
    public void nGameFrameInput(@NRPCParam("inputs") List<Object> inputs){
        if(Objects.isNull(nSyncFPSMode)) return;
        nSyncFPSMode.addFPSInfos(inputs);
    }

    /**
     * 开始游戏
     */
    @NGameRPCMethod
    public void nGameStart(){

        if(Objects.nonNull(nSyncFPSMode)) return;

        String frames = env.getProperty("ngame.default");

        //创建帧同步对象
        nSyncFPSMode = new NSyncFPSMode<>();
        nSyncFPSMode.setIntervalTime(66); //设置同步帧
        if(Objects.nonNull(frames)) {
            nSyncFPSMode.setDataList(JSONObject.parseObject(frames,new TypeReference<CopyOnWriteArrayList<NFPSInfo<Object>>>(){}));
            nSyncFPSMode.setIndex(nSyncFPSMode.getDataList().size());
        }
        //添加同步功能
        addRegister(nSyncFPSMode);

        //开启同步
        nSyncFPSMode.start();
        room.setIsStartGame(true);
        System.out.println("SNCocosFrameAction - nGameStart : 开始游戏");

        //通知客户端
        clients.values().forEach(iClient -> {
            iClient.getCnPicoparkAction().nGameRoomInfo(this.room);
        });

    }


    /**
     * 同步模式回调
     */
    @NSyncFPSMethod
    public void nGameSyncCallBack(String uuid, NFPSInfo<Object> nFPSInfo){

        if(Objects.isNull(clients)) return;

        //向所有客户端 发送帧数据
        clients.values().forEach(client -> {
            client.getCnPicoparkAction().nGameSyncInputCallBack(nFPSInfo);
        });

    }

    /**
     * 结束游戏
     */
    @NGameRPCMethod
    public void nGameEnd(){

        if(Objects.isNull(nSyncFPSMode)) return;

        nSyncFPSMode.end();
        nSyncFPSMode = null;
        room = null;

        //通知客户端
        clients.values().forEach(iClient -> {
            iClient.getCnPicoparkAction().nGameEndGame();
        });

        System.out.println("SNCocosFrameAction - nGameEnd : 结束游戏");

    }


    /**
     * 加入游戏
     */
    @NGameRPCMethod
    public void nJoinGame(PicoparkNClient client){

        //如果没有房间则创建房间
        if(Objects.isNull(room)) this.room = new PicoparkRoom();

        //游戏开始则加入不了 并且人数不能超过6人
        if(room.getIsStartGame() || room.getPlayers().size() >= 6) return;

        //加入游戏
        if(!this.room.getPlayers().contains(client.getUuid())){

            room.getPlayers().add(client.getUuid());

        }

        //通知客户端
        clients.values().forEach(iClient -> {
            iClient.getCnPicoparkAction().nGameRoomInfo(this.room);
        });

    }

    //记入日志
    @NGameRPCMethod
    public void nLog(PicoparkNClient client,@NRPCParam("log") String log){

        StringBuilder logs = this.logs.get(client.getUuid());
        if(Objects.isNull(logs)){
            logs = new StringBuilder();
            this.logs.put(client.getUuid(),logs);
        }
        logs.append(log+"\n");

    }

    /**
     * 退出游戏
     */
    @NGameRPCMethod
    public void nLeaveGame(PicoparkNClient client){

        if(Objects.isNull(room)) return;

        //如果游戏开始则不能退出
        if(room.getIsStartGame()) return;

        //退出游戏
        room.getPlayers().remove(client.getUuid());

        //通知客户端
        clients.values().forEach(iClient -> {
            iClient.getCnPicoparkAction().nGameRoomInfo(this.room);
        });

    }


}
